package com.magima.core.basicstorage;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.Handler;
import android.os.Message;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.magima.core.app.BaseApplication;
import com.magima.core.app.ExceptionConstants;
import com.magima.core.app.IExceptionCallback;
import com.magima.core.basic.Collection;
import com.magima.core.basic.Model;
import com.magima.core.basic.Storage;
import com.magima.core.basic.option.StorageOptionConstants;
import com.magima.core.connect.ServerAsyncTask;
import com.magima.core.connect.listener.ServerDataListener;
import com.magima.core.connect.listener.ServerTaskListener;
import com.magima.core.repository.Repository;
import com.magima.core.ui.LoadingUIProvider;

public class UrlCollectionStorage<T> extends Storage<T> {

	private static LoadingUIProvider globalLoadingUIProvider;
	private Gson mGson;
	private Lock mLock = new ReentrantLock(true);

	public static void setGlobalLoadingUIProvider(LoadingUIProvider onLoadingUIChanged){
		globalLoadingUIProvider = onLoadingUIChanged;
	}
	
	public interface Corrector {
		public String correct(String input);
	}

	public interface ResultToList<T> {
		public List<T> convert(String result);
	}

	public interface ResultToObj<T> {
		public T convert(String result);
	}
	
	public interface ResultToSucceed {
		public boolean convert(String result);
	}

	private Class<?> typeOfT;
	private String url;
	private Corrector corrector;
	private Context context;
	private Repository repository = null;
	
	public UrlCollectionStorage(Context context, String url, Class<?> typeOfT,
			Corrector corrector) {
		this.url = url;
		this.corrector = corrector;
		this.context = context;
		this.typeOfT = typeOfT;
		mGson = new GsonBuilder().create();
	}
	
	protected Gson getGson(){
		return mGson;
	}

	public Corrector getCorrector() {
		return corrector;
	}

	public void setCorrector(Corrector corrector) {
		this.corrector = corrector;
	}

	protected Repository getRepository() {
		return repository;
	}

	public void setRepository(Repository repository) {
		this.repository = repository;
		if ( repository != null ) {
			Lock lock = repository.getLock(); //如果repository有锁，就用repository的锁，否则就用自己的锁
			if ( lock != null )
				mLock = lock;
		}
	}
	
	@Override
	public Storage<T> duplicate(){
		return new UrlCollectionStorage<T>(context, url, typeOfT, corrector);
	}

	private ResultToObj<T> defaultResultToObj = new ResultToObj<T>() {
		@SuppressWarnings("unchecked")
		@Override
		public T convert(String result) {
			try {
				if ( result.trim().equals("{}"))
					return null;
				Gson gson = new GsonBuilder().create();
				T o = (T) gson.fromJson(result, typeOfT);
				return o;
			} catch (Exception e) {
				return null;
			}
		}
	};

	private static class MyHandlerServerResult<T2> extends Handler{
		private boolean _need_progress;
		private ServerDataListener<T2> listener;
		private String result;
		private WeakReference<Context> context;
		public MyHandlerServerResult(boolean need_progress, ServerDataListener<T2> listener,String result, Context context){
			_need_progress = need_progress;
			this.listener = listener;
			this.result = result;
			this.context = new WeakReference<Context>(context);
		}
		@Override  
		public void handleMessage(Message msg) {
			@SuppressWarnings("unchecked")
			T2 datas = (T2) msg.obj;
			if ( _need_progress && globalLoadingUIProvider != null) {
				if ( context.get() != null )
					globalLoadingUIProvider.stopLoadingUI(context.get());
			}
			if ( datas == null ) {
                if (listener != null) {
                    showJsonSyntaxException(context.get());
                    listener.onError();
                }
			} else {
				if (listener != null)
					listener.onSuccess(datas, result);
			}
		}
	}
	
	private static class MyLocalRepositoryHandler<T3> extends Handler{	
		private boolean _need_progress;
		private boolean rf;
		private WeakReference<Context> context;
		private String ul;
		private String md;
		private HashMap<String, String> ps;
		private boolean ns;
		private ServerTaskListener sr;
		private ServerDataListener<List<T3>> listener;
		private int st;
		public MyLocalRepositoryHandler(boolean repositoryFirst, Context context, String url, String method,
				HashMap<String, String> params, boolean need_progress,
				ServerTaskListener serverTasklistener, ServerDataListener<List<T3>> listener, int socketTimeout){
			rf = repositoryFirst;
			this.context = new WeakReference<Context>(context);
			this.ul = url;
			this.md = method;
			this.ps = params;
			this.ns = need_progress;
			this.sr = serverTasklistener;
			this.listener = listener;
			this._need_progress = need_progress;
			this.st = socketTimeout;
		}
		@Override  
		public void handleMessage(Message msg) {
			@SuppressWarnings("unchecked")
			List<T3> datas = (List<T3>) msg.obj;
			if ( _need_progress && globalLoadingUIProvider != null) {
				if ( context.get() != null )
					globalLoadingUIProvider.stopLoadingUI(context.get());
			}
			if ( rf && datas.size() == 0 ) {
				if ( context.get() != null ) {
					ServerAsyncTask task = new ServerAsyncTask(context.get(), ul, md, ps, ns, false, sr, st);
					task.execute();
				}
			} else {
				if (listener != null)
					listener.onSuccess(datas, "");
			}
		}
	}
	
	protected void saveToRepository( T o, Collection<T> collection, HashMap<String, Object> options ){
		mLock.lock();
		try {
			repository.saveString(collection.getId(o),
					mGson.toJson(o));
		} finally {
			mLock.unlock();
		}
	}
	
	protected void saveToRepository( T o, Model<T> model , HashMap<String, Object> options){
		mLock.lock();
		try {
			String id = model.getCollection() != null ? model.getCollection().getId(o) : "";
			repository.saveString(id, mGson.toJson(o));
		} finally {
			mLock.unlock();
		}
	}
	
	protected void saveToRepositoryBulk( List<T> datas, Collection<T> collection, HashMap<String, Object> options){
		String[] keys = new String[datas.size()];
		String[] values = new String[datas.size()];
		Gson gson = new GsonBuilder().create();

		for ( int i = 0; i < datas.size(); i++ ) {
			T data = datas.get(i);
			keys[i] = collection.getId(data);
			values[i] = gson.toJson(data,typeOfT);			
		}
		try {
			repository.saveStrings(keys, values);
		} catch ( UnsupportedOperationException e ){
			for ( int i = 0; i < datas.size(); i++ ) {
				repository.saveString(keys[i], values[i]);
			}
		}
	}
	
	protected List<String> loadAllFromRepository(HashMap<String, Object> options){
		return repository.loadAllString();
	}

	@Override
	@SuppressWarnings("unchecked")
	public void read(final Collection<T> collection,
			final ServerDataListener<List<T>> listener,
			final HashMap<String, Object> options) {
		String url = this.url;
		String method = "GET";
		HashMap<String, String> params = null;
		ServerTaskListener serverTasklistener = null;
		ResultToList<T> resultToList = null;
		boolean onlyRepository = false, pageFetchAfter = false, pageFetchBefore = false, repositoryFirst = false;
		if (collection.getUrlGenerator() != null) {
			url = collection.getUrlGenerator().getUrl(collection);
		}
		Context context = this.context;
		int socketTimeout = 0;
		boolean cancelable = false;
		OnCancelListener onCancelListener = null;
		boolean need_progress = false;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = (HashMap<String, String>) options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_LIST) != null) {
				resultToList = (ResultToList<T>) options.get(StorageOptionConstants.OPTION_RESULT_TO_LIST);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
			if (options.get(StorageOptionConstants.OPTION_PAGE_FETCH_AFTER) != null) {
				pageFetchAfter = (Boolean) options
						.get(StorageOptionConstants.OPTION_PAGE_FETCH_AFTER);
			}
			if (options.get(StorageOptionConstants.OPTION_PAGE_FETCH_BEFORE) != null) {
				pageFetchBefore = (Boolean) options
						.get(StorageOptionConstants.OPTION_PAGE_FETCH_BEFORE);
			}
			if (options.get(StorageOptionConstants.OPTION_REPOSITORY_FIRST) != null) {
				repositoryFirst = (Boolean) options
						.get(StorageOptionConstants.OPTION_REPOSITORY_FIRST);
			}
			if (options.get(StorageOptionConstants.OPTION_SOCKET_TIMEOUT) != null) {
				socketTimeout = (Integer)options.get(StorageOptionConstants.OPTION_SOCKET_TIMEOUT);
			}
			if (options.get(StorageOptionConstants.OPTION_CANCELABLE) != null) {
				cancelable = (Boolean)options.get(StorageOptionConstants.OPTION_CANCELABLE);
			}
			if (options.get(StorageOptionConstants.OPTION_ON_CACNEL_LISTENER) != null) {
				onCancelListener = (OnCancelListener)options.get(StorageOptionConstants.OPTION_ON_CACNEL_LISTENER);
				if ( onCancelListener == null ) {
					onCancelListener = new OnCancelListener(){
						@Override
						public void onCancel(DialogInterface arg0) {
						}
					};
				}
			}
		}
		final Context _context = context;
		final Gson gson = new GsonBuilder().create();
		final boolean _need_progress = need_progress;
		if (resultToList == null) {
			resultToList = new ResultToList<T>() {
				@Override
				public List<T> convert(String result) {
					List<T> data = new ArrayList<T>();
					try {
						/*T[] temp = (T[]) gson.fromJson(result, typeOfArrayT);
						for (int i = 0, length = temp.length; i < length; i++) {
							data.add(temp[i]);
						}*/
						JSONArray jsonArray = new JSONArray(result);

						for (int i = 0, length = jsonArray.length(); i < length; i++) {
							JSONObject jsonOb = (JSONObject) jsonArray.opt(i);
							String str = jsonOb.toString();
							T o = (T) gson.fromJson(str, typeOfT);
							data.add(o);
						}
					}catch(JsonSyntaxException e){
						BaseApplication app = BaseApplication.fromContext(_context);
						IExceptionCallback toastCallback = app.getExceptionManager().findByType(ExceptionConstants.CODE_JSON_SYNTAX_EXCEPTION);
						if(toastCallback != null){
							toastCallback.onEvent(_context, ExceptionConstants.CODE_JSON_SYNTAX_EXCEPTION, 0);
						}
						e.printStackTrace();
						return null;
					}catch (Exception e) {
						e.printStackTrace();
						return null;
					}
					return data;
				}
			};
		}
		final ResultToList<T> _resultToList = resultToList;
		final boolean _pageFetchAfter = pageFetchAfter, _pageFetchBefore = pageFetchBefore;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(final String result) {
					
					
					final Handler hander = new MyHandlerServerResult<List<T>>(_need_progress, listener, result, _context);
					Runnable runnable = new Runnable(){
						@Override
						public void run() {
							String _result = result;
							if (corrector != null)
								_result = corrector.correct(result);

							List<T> datas = null;
							if (_resultToList != null) {
								datas = _resultToList.convert(_result);
							}
							
							Message msg = new Message();
							msg.obj = datas;
							hander.sendMessage(msg);
							
							new MyWriteRepositoryThread(datas, collection, options, _pageFetchAfter, _pageFetchBefore).start();
						}
					};
					Thread thread = new Thread(runnable);
					thread.start();					
				}

				@Override
				public void onError(int errorCode) {
					if ( _need_progress && globalLoadingUIProvider != null)
						globalLoadingUIProvider.stopLoadingUI(_context);
					if (repository != null) {
						if ( _pageFetchAfter || _pageFetchBefore ){
							if (listener != null)
								listener.onError();
						}else{
							final Handler hander = new MyHandlerServerResult<List<T>>(_need_progress, listener, "", _context);
							Runnable runnable = new Runnable(){
								@Override
								public void run() {
									List<String> strings;
									mLock.lock();
									try {
										strings = loadAllFromRepository(options);
									} finally {
										mLock.unlock();
									}
									List<T> datas = new ArrayList<T>();
									for (String str : strings) {
										T o = (T) gson.fromJson(str, typeOfT);
										datas.add(o);
									}
									
									Message msg = new Message();
									msg.obj = datas;
									hander.sendMessage(msg);
								}
							};
							Thread thread = new Thread(runnable, "repository fetch");
							thread.start();
						}
					} else {
						if (listener != null)
							listener.onError();
					}
				}
			};
		}
		
		if ( onlyRepository || repositoryFirst) {
			if (repository != null) {
			 	final Handler mHandler = new MyLocalRepositoryHandler<T>(repositoryFirst, _context, url, method, params, need_progress, serverTasklistener, listener, socketTimeout );
			 
				Runnable runnable = new Runnable(){
					@Override
					public void run() {
						List<String> strings;
						mLock.lock();
						try {
							strings = loadAllFromRepository(options);
						} finally {
							mLock.unlock();
						}
						List<T> data = new ArrayList<T>();
						for (String str : strings) {
							T o = (T) gson.fromJson(str, typeOfT);
							data.add(o);
						}

						Message msg = new Message();
						msg.obj = data;
						mHandler.sendMessage(msg);
					}
				};
				if ( need_progress && globalLoadingUIProvider != null)
					globalLoadingUIProvider.startLoadingUI(context, cancelable ? onCancelListener : null);
				Thread thread = new Thread(runnable);
				thread.start();
			} else {
				if (listener != null)
					listener.onError();
			}
		} else {
			if ( need_progress && globalLoadingUIProvider != null)
				globalLoadingUIProvider.startLoadingUI(context, cancelable ? onCancelListener : null);
			ServerAsyncTask task = new ServerAsyncTask(context, url, method, params, false,
					false, serverTasklistener, socketTimeout );
			task.execute();
		}
	}

	class MyWriteRepositoryThread extends Thread{
		private List<T> datas;
		private Collection<T> collection;
		private HashMap<String, Object> options;
		private boolean _pageFetchAfter;
		private boolean _pageFetchBefore;
		
		public MyWriteRepositoryThread(List<T> datas, Collection<T> collection, HashMap<String, Object> options,
				boolean _pageFetchAfter, boolean _pageFetchBefore){
			this.datas = datas;
			this.collection = collection;
			this.options = options;
			this._pageFetchAfter = _pageFetchAfter;
			this._pageFetchBefore = _pageFetchBefore;
		}
		
		@Override
		public void run() {
			if (datas != null) {
				if (repository != null) {
					mLock.lock();
					try {
						if ( !_pageFetchAfter && !_pageFetchBefore )
							repository.remove();	
						saveToRepositoryBulk(datas, collection, options);
					} finally {
						mLock.unlock();
					}									
				}
			}
		}
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public void read(final Model<T> model,
			final ServerDataListener<T> listener,
			final HashMap<String, Object> options) {
		String url = this.url;
		String method = "GET";
		ServerTaskListener serverTasklistener = null;
		ResultToObj<T> resultToObj = defaultResultToObj;

		if (model.getUrlGenerator() != null) {
			url = model.getUrlGenerator().getUrl(model);
		}
		Context context = this.context;
		HashMap<String, String> params = null;
		boolean onlyRepository = false;
		boolean need_progress = false;
		boolean isString = false;
		int socketTimeout = 0;
		boolean cancelable = false;
		OnCancelListener onCancelListener = null;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = (HashMap<String, String>) options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ) != null) {
				resultToObj = (ResultToObj<T>) options.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
			if (options.get(StorageOptionConstants.OPTION_IS_STRING) != null) {
				isString = (Boolean) options.get(StorageOptionConstants.OPTION_IS_STRING);
			}
			if (options.get(StorageOptionConstants.OPTION_SOCKET_TIMEOUT) != null) {
				socketTimeout = (Integer) options.get(StorageOptionConstants.OPTION_SOCKET_TIMEOUT);
			}
			if (options.get(StorageOptionConstants.OPTION_CANCELABLE) != null) {
				cancelable = (Boolean)options.get(StorageOptionConstants.OPTION_CANCELABLE);
			}
			if (options.get(StorageOptionConstants.OPTION_ON_CACNEL_LISTENER) != null) {
				onCancelListener = (OnCancelListener)options.get(StorageOptionConstants.OPTION_ON_CACNEL_LISTENER);
				if ( onCancelListener == null ) {
					onCancelListener = new OnCancelListener(){
						@Override
						public void onCancel(DialogInterface arg0) {
						}
					};
				}
			}
		}
		final ResultToObj<T> _resultToObj = resultToObj;
        final Context _context = context;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(String result) {
					if (corrector != null)
						result = corrector.correct(result);
					T o = null;
					if (_resultToObj != null)
						o = _resultToObj.convert(result);
					if (o != null) {
						if(repository != null){
							saveToRepository(o, model, options);
						}
						if (listener != null)
							listener.onSuccess(o, result);
					} else {
                        if (listener != null) {
                            showJsonSyntaxException(_context);
                            listener.onError();
                        }
					}
				}

				@Override
				public void onError(int errorCode) {
					T o = null;
					if (repository != null) {
						String data;
						mLock.lock();
						String id = model.getCollection() != null ? model.getCollection().getId(model.getModel()) : "";
						try {
							data = repository.loadString(id);
						} finally {
							mLock.unlock();
						}
						if (data != null) {
							o = _resultToObj.convert(data);
						}
					}
					if (o != null) {
						if (listener != null)
							listener.onSuccess(o, "");
					} else {
						if (listener != null)
							listener.onError();
					}
				}
			};
		}
		if ( onlyRepository ) {
			T o = null;
			if (repository != null) {
				String data;
				mLock.lock();
				String id = model.getCollection() != null ? model.getCollection().getId(model.getModel()) : "";
				try {
					data = repository.loadString(id);
				} finally {
					mLock.unlock();
				}
				if (data != null) {
					o = _resultToObj.convert(data);
				}
			}
			if (o != null) {
				if (listener != null)
					listener.onSuccess(o, "");
			} else {
				if (listener != null)
					listener.onError();
			}
		} else {
			ServerAsyncTask task = new ServerAsyncTask(context, url, method, params, need_progress,
					isString, serverTasklistener, socketTimeout,
					cancelable ? onCancelListener : null);
			task.execute();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public void create(final Collection<T> collection, T model,
			final ServerDataListener<T> listener,
			final HashMap<String, Object> options) {
		String url = this.url;
		String method = "POST";
		HashMap<String, String> params = null;
		ServerTaskListener serverTasklistener = null;
		ResultToObj<T> resultToObj = defaultResultToObj;
		Context context = this.context;
		boolean isString = false;
		boolean need_progress = false;
		boolean onlyRepository = false;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = (HashMap<String, String>) options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options
						.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ) != null) {
				resultToObj = (ResultToObj<T>) options
						.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options
						.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options
						.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_IS_STRING) != null) {
				isString = (Boolean) options
						.get(StorageOptionConstants.OPTION_IS_STRING);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options
						.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
		}
		final ResultToObj<T> _resultToObj = resultToObj;
        final Context _context = context;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(String result) {
					if (corrector != null)
						result = corrector.correct(result);
					T o = null;
					if (_resultToObj != null)
						o = _resultToObj.convert(result);
					if (o != null) {
						if(repository != null){
							saveToRepository(o, collection,options);
						}
						if (listener != null)
							listener.onSuccess(o, result);
					} else {
                        if (listener != null) {
                            showJsonSyntaxException(_context);
                            listener.onError();
                        }
					}
				}

				@Override
				public void onError(int errorCode) {
					if (listener != null)
						listener.onError();
				}
			};
		}
		if ( onlyRepository ) {
			if(repository != null){
				saveToRepository(model, collection, options);
			}
			if (listener != null)
				listener.onSuccess(model, mGson.toJson(model));
		} else {
			ServerAsyncTask task = new ServerAsyncTask(context, url, method, params, need_progress, isString, serverTasklistener);
			task.execute();
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public void delete(final Collection<T> collection, final Model<T> model,
			final ServerDataListener<T> listener,
			HashMap<String, Object> options) {
		String url = this.url;
		String method = "DELETE";
//		HashMap<String, String> params = null;
		Object params = null;
		ServerTaskListener serverTasklistener = null;
		if (model.getUrlGenerator() != null) {
			url = model.getUrlGenerator().getUrl(model);
		}
		Context context = this.context;
		boolean onlyRepository = false;
		boolean need_progress = false;
		ResultToSucceed resultToSucceed = null;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options
						.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options
						.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options
						.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options
						.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_SUCCEED) != null) {
				resultToSucceed = (ResultToSucceed) options
						.get(StorageOptionConstants.OPTION_RESULT_TO_SUCCEED);
			}
		}
		final ResultToSucceed _resultToSucceed = resultToSucceed;
        final Context _context = context;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(String result) {
					boolean succeed = true;
					if (_resultToSucceed!=null) {
						succeed = _resultToSucceed.convert(result);					
					}
					if ( !succeed ) {
                        if (listener != null) {
                            showJsonSyntaxException(_context);
                            listener.onError();
                        }
					} else {
						if (repository != null) {
							mLock.lock();
							try {
								repository.remove(collection.getId(model.getModel()));
							} finally {
								mLock.unlock();
							}
						}
						if (listener != null)
							listener.onSuccess(model.getModel(), result);
					}
				}

				@Override
				public void onError(int errorCode) {
					if (listener != null)
						listener.onError();
				}
			};
		}
		if ( onlyRepository ) {
			if (repository != null) {
				mLock.lock();
				try {
					repository.remove(collection.getId(model.getModel()));
				} finally {
					mLock.unlock();
				}
			}
			if (listener != null)
				listener.onSuccess(model.getModel(), "");
		}else {
			ServerAsyncTask task = null;
			if(params instanceof String){
				task = new ServerAsyncTask(context, url, method, (String)  params, need_progress, serverTasklistener);
			}else if(params instanceof HashMap || params == null){
				task = new ServerAsyncTask(context, url, method, (HashMap<String, String>) params, need_progress, false, serverTasklistener);
			}
			task.execute();
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void update(final Model<T> model, final T data,
			final ServerDataListener<T> listener,
			final HashMap<String, Object> options) {
		String url = this.url;
		String method = "PUT";
		HashMap<String, String> params = null;
		ServerTaskListener serverTasklistener = null;
		ResultToObj<T> resultToObj = defaultResultToObj;
		boolean onlyRepository = false;
		//final String idAttribute = model.getCollection() != null ? model
		//		.getCollection().getIdAttribute() : null;
		if (model.getUrlGenerator() != null) {
			url = model.getUrlGenerator().getUrl(model);
		}
		Context context = this.context;
		boolean isString = false;
		boolean need_progress = false;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = (HashMap<String, String>) options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options
						.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ) != null) {
				resultToObj = (ResultToObj<T>) options
						.get(StorageOptionConstants.OPTION_RESULT_TO_OBJ);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options
						.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options
						.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_IS_STRING) != null) {
				isString = (Boolean) options
						.get(StorageOptionConstants.OPTION_IS_STRING);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options
						.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
		}
		final ResultToObj<T> _resultToObj = resultToObj;
        final Context _context = context;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(String result) {
					if (corrector != null)
						result = corrector.correct(result);
					T o = null;
					if (_resultToObj != null)
						o = _resultToObj.convert(result);
					if ( o == null ) {
                        if (listener != null) {
                            showJsonSyntaxException(_context);
                            listener.onError();
                        }
					} else {
						T m = o;
						if (repository != null) {
							saveToRepository( m, model , options);
						}
						if (listener != null)
							listener.onSuccess(m, result);
					}
				}

				@Override
				public void onError(int errorCode) {
					if (listener != null)
						listener.onError();
				}
			};
		}
		if ( onlyRepository ) {
			T m = data;
			if (repository != null) {				
				saveToRepository( m, model, options );
			}
			if (listener != null)
				listener.onSuccess(data, mGson.toJson(m));
		} else {
			ServerAsyncTask task = new ServerAsyncTask(context, url, method, params, need_progress, isString, serverTasklistener);
			task.execute();
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void deleteAll(final Collection<T> collection, final ServerDataListener<T> listener,
			final HashMap<String, Object> options){
		String url = this.url;
		String method = "DELETE";
//		HashMap<String, String> params = null;
		Object params = null;
		ServerTaskListener serverTasklistener = null;
		
		Context context = this.context;
		boolean onlyRepository = false;
		boolean need_progress = false;
		ResultToSucceed resultToSucceed = null;
		if (options != null) {
			if (options.get(StorageOptionConstants.OPTION_URL) != null) {
				url = (String) options.get(StorageOptionConstants.OPTION_URL);
			}
			if (options.get(StorageOptionConstants.OPTION_METHOD) != null) {
				method = (String) options.get(StorageOptionConstants.OPTION_METHOD);
			}
			if (options.get(StorageOptionConstants.OPTION_PARAMS) != null) {
				params = options.get(StorageOptionConstants.OPTION_PARAMS);
			}
			if (options.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER) != null) {
				serverTasklistener = (ServerTaskListener) options
						.get(StorageOptionConstants.OPTION_SERVER_TASK_LISTENER);
			}
			if (options.get(StorageOptionConstants.OPTION_CONTEXT) != null) {
				context = (Context) options
						.get(StorageOptionConstants.OPTION_CONTEXT);
			}
			if (options.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY) != null) {
				onlyRepository = (Boolean) options
						.get(StorageOptionConstants.OPTION_ONLY_REPOSITORY);
			}
			if (options.get(StorageOptionConstants.OPTION_NEED_PROGRESS) != null) {
				need_progress = (Boolean) options
						.get(StorageOptionConstants.OPTION_NEED_PROGRESS);
			}
			if (options.get(StorageOptionConstants.OPTION_RESULT_TO_SUCCEED) != null) {
				resultToSucceed = (ResultToSucceed) options
						.get(StorageOptionConstants.OPTION_RESULT_TO_SUCCEED);
			}
		}
		final ResultToSucceed _resultToSucceed = resultToSucceed;
        final Context _context = context;
		if (serverTasklistener == null) {
			serverTasklistener = new ServerTaskListener() {
				@Override
				public void onSuccess(String result) {
					boolean succeed = true;
					if (_resultToSucceed!=null) {
						succeed = _resultToSucceed.convert(result);					
					}
					if ( !succeed ) {
						if (listener != null) {
                            showJsonSyntaxException(_context);
                            listener.onError();
                        }
					} else {
						if (repository != null) {
							mLock.lock();
							try {
								repository.remove();
							} finally {
								mLock.unlock();
							}
						}
						if (listener != null)
							listener.onSuccess(null, result);
					}
				}

				@Override
				public void onError(int errorCode) {
					if (listener != null)
						listener.onError();
				}
			};
		}
		if ( onlyRepository ) {
			if (repository != null) {
				mLock.lock();
				try {
					repository.remove();
				} finally {
					mLock.unlock();
				}
			}
			if (listener != null)
				listener.onSuccess(null, "");
		}else {
			ServerAsyncTask task = null;
			if(params instanceof String){
				task = new ServerAsyncTask(context, url, method, (String)  params, need_progress, serverTasklistener);
			}else if(params instanceof HashMap || params == null){
				task = new ServerAsyncTask(context, url, method, (HashMap<String, String>) params, need_progress, false, serverTasklistener);
			}
			task.execute();
		}
	}

    private static void showJsonSyntaxException(Context context){
        if(context != null){
            BaseApplication app = BaseApplication.fromContext(context);
            IExceptionCallback callback = app.getExceptionManager().getDefaultType();
            if(callback != null){
                callback.onEvent(context, ExceptionConstants.CODE_JSON_SYNTAX_EXCEPTION, 0);
            }
        }
    }
}
